// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package istio.workload;
option go_package="pkg/workloadapi";

// Address represents a unique address.
//
// Address joins two sub-resources, Workload and Service, to support querying by IP address.
// Address is intended to be able to be looked up on-demand, allowing a client
// to answer a question like "what is this IP address", similar to a reverse DNS lookup.
//
// Each resource will have a mesh-wide unique opaque name, defined in the individual messages.
// In addition, to support lookup by IP address, they will have *alias* names for each IP the resource represents.
// There may be multiple aliases for the same resource (examples: service in multiple networks, or a dual-stack workload).
// Aliases are keyed by network/IP address. Example: "default/1.2.3.4".
//
// In some cases, we do not know the IP address of a Workload. For instance, we may simply know
// that there is a workload behind a gateway, and rely on the gateway to handle the rest.
// In this case, the key format will be "resource-uid". The resource can be a Pod, WorkloadEntry, etc.
// These resources cannot be looked up on-demand.
//
// In some cases, we do not know the IP address of a Service. These services cannot be used for matching
// outbound traffic, as we only have L4 attributes to route based on. However,
// they can be used for Gateways.
// In this case, the key format will be "network/hostname".
// These resources cannot be looked up on-demand.
message Address {
  oneof type {
    // Workload represents an individual workload.
    // This could be a single Pod, a VM instance, etc.
    Workload workload = 1;
    // Service represents a service - a group of workloads that can be accessed together.
    Service service = 2;
  }
}

// Service represents a service - a group of workloads that can be accessed together.
// The xds primary key is "namespace/hostname".
// Secondary (alias) keys are the unique `network/IP` pairs that the service can be reached at.
message Service {
  // Name represents the name for the service.
  // For Kubernetes, this is the Service name.
  string name = 1;
  // Namespace represents the namespace for the service.
  string namespace = 2;
  // Hostname represents the FQDN of the service.
  // For Kubernetes, this would be <name>.<namespace>.svc.<cluster domain>.
  string hostname = 3;
  // Address represents the addresses the service can be reached at.
  // There may be multiple addresses for a single service if it resides in multiple networks,
  // multiple clusters, and/or if it's dual stack (TODO: support dual stack).
  // For a headless kubernetes service, this list will be empty.
  repeated NetworkAddress addresses = 4;
  // Ports for the service.
  // The target_port may be overridden on a per-workload basis.
  repeated Port ports = 5;
  // Optional; if set, the SAN to verify for TLS connections.
  // Typically, this is not set and per-workload identity is used to verify
  repeated string subject_alt_names = 6;
}

// Workload represents a workload - an endpoint (or collection behind a hostname).
// The xds primary key is "uid" as defined on the workload below.
// Secondary (alias) keys are the unique `network/IP` pairs that the workload can be reached at.
message Workload {
  // UID represents a globally unique opaque identifier for this workload.
  // For k8s resources, it is recommended to use the more readable format:
  //
  // cluster/group/kind/namespace/name/section-name
  //
  // As an example, a ServiceEntry with two WorkloadEntries inlined could become
  // two Workloads with the following UIDs:
  // - cluster1/networking.istio.io/v1alpha3/ServiceEntry/default/external-svc/endpoint1
  // - cluster1/networking.istio.io/v1alpha3/ServiceEntry/default/external-svc/endpoint2
  //
  // For VMs and other workloads other formats are also supported; for example,
  // a single UID string: "0ae5c03d-5fb3-4eb9-9de8-2bd4b51606ba"
  string uid = 20;
  // Name represents the name for the workload.
  // For Kubernetes, this is the pod name.
  // This is just for debugging and may be elided as an optimization.
  string name = 1;
  // Namespace represents the namespace for the workload.
  // This is just for debugging and may be elided as an optimization.
  string namespace = 2;

  // Address represents the IPv4/IPv6 address for the workload.
  // This should be globally unique.
  // This should not have a port number.
  // Each workload must have at least either an address or hostname; not both.
  repeated bytes addresses = 3;

  // The hostname for the workload to be resolved by the ztunnel.
  // DNS queries are sent on-demand by default.
  // If the resolved DNS query has several endpoints, the request will be forwarded
  // to the first response.
  //
  // At a minimum, each workload must have either an address or hostname. For example,
  // a workload that backs a Kubernetes service will typically have only endpoints. A
  // workload that backs a headless Kubernetes service, however, will have both
  // addresses as well as a hostname used for direct access to the headless endpoint.
  string hostname = 21;

  // Network represents the network this workload is on. This may be elided for the default network.
  // A (network,address) pair makeup a unique key for a workload *at a point in time*.
  string network = 4;

  // Protocol that should be used to connect to this workload.
  TunnelProtocol tunnel_protocol = 5;

  // The SPIFFE identity of the workload. The identity is joined to form spiffe://<trust_domain>/ns/<namespace>/sa/<service_account>.
  // TrustDomain of the workload. May be elided if this is the mesh wide default (typically cluster.local)
  string trust_domain = 6;
  // ServiceAccount of the workload. May be elided if this is "default"
  string service_account = 7;

  // If present, the waypoint proxy for this workload.
  // All incoming requests must go through the waypoint.
  GatewayAddress waypoint = 8;

  // If present, East West network gateway this workload can be reached through.
  // Requests from remote networks should traverse this gateway.
  GatewayAddress network_gateway = 19;

  // Name of the node the workload runs on
  string node = 9;

  // CanonicalName for the workload. Used for telemetry.
  string canonical_name = 10;
  // CanonicalRevision for the workload. Used for telemetry.
  string canonical_revision = 11;
  // WorkloadType represents the type of the workload. Used for telemetry.
  WorkloadType workload_type = 12;
  // WorkloadName represents the name for the workload (of type WorkloadType). Used for telemetry.
  string workload_name = 13;

  // If set, this indicates a workload expects to directly receive tunnel traffic.
  // In ztunnel, this means:
  // * Requests *from* this workload do not need to be tunneled if they already are tunneled by the tunnel_protocol.
  // * Requests *to* this workload, via the tunnel_protocol, do not need to be de-tunneled.
  bool native_tunnel = 14;

  // The services for which this workload is an endpoint.
  // The key is the NamespacedHostname string of the format namespace/hostname.
  map<string, PortList> services = 22;

  // A list of authorization policies applicable to this workload.
  // NOTE: this *only* includes Selector based policies. Namespace and global polices
  // are returned out of band.
  // Authorization policies are only valid for workloads with `addresses` rather than `hostname`.
  repeated string authorization_policies = 16;

  WorkloadStatus status = 17;

  // The cluster ID that the workload instance belongs to
  string cluster_id = 18;

  // Reservations for deleted fields.
  reserved 15;
}

enum WorkloadStatus {
  // Workload is healthy and ready to serve traffic.
  HEALTHY = 0;
  // Workload is unhealthy and NOT ready to serve traffic.
  UNHEALTHY = 1;
}

enum WorkloadType {
  DEPLOYMENT = 0;
  CRONJOB = 1;
  POD = 2;
  JOB = 3;
}

// PorList represents the ports for a service
message PortList {
  repeated Port ports = 1;
}

message Port {
  // Port the service is reached at (frontend).
  uint32 service_port = 1;
  // Port the service forwards to (backend).
  uint32 target_port = 2;
}

// TunnelProtocol indicates the tunneling protocol for requests.
enum TunnelProtocol {
  // NONE means requests should be forwarded as-is, without tunneling.
  NONE = 0;
  // HBONE means requests should be tunneled over HTTP.
  // This does not dictate HTTP/1.1 vs HTTP/2; ALPN should be used for that purpose.
  HBONE = 1;
  // Future options may include things like QUIC/HTTP3, etc.
}

// GatewayAddress represents the address of a gateway
message GatewayAddress {
  // address can either be a hostname (ex: gateway.example.com) or an IP (ex: 1.2.3.4).
  oneof destination {
    // TODO: add support for hostname lookup
    NamespacedHostname hostname = 1;
    NetworkAddress address = 2;
  }
  // port to reach the gateway at for mTLS HBONE connections
  uint32 hbone_mtls_port = 3;
  // port to reach the gateway at for single tls HBONE connections
  // used for sending unauthenticated traffic originating outside the mesh to a waypoint-enabled destination
  // A value of 0 = unset
  uint32 hbone_single_tls_port = 4;
}

// NetworkAddress represents an address bound to a specific network.
message NetworkAddress {
  // Network represents the network this address is on.
  string network = 1;
  // Address presents the IP (v4 or v6).
  bytes address = 2;
}

// NamespacedHostname represents a service bound to a specific namespace.
message NamespacedHostname {
  // The namespace the service is in.
  string namespace = 1;
  // hostname (ex: gateway.example.com)
  string hostname = 2;
}
